package org.jeecg.modules.zhima.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.zhima.admin.entity.*;
import org.jeecg.modules.zhima.admin.service.IZmGameAwardService;
import org.jeecg.modules.zhima.admin.service.IZmGameBackupService;
import org.jeecg.modules.zhima.admin.service.IZmGamePlayerService;
import org.jeecg.modules.zhima.admin.service.IZmGameService;
import org.jeecg.modules.zhima.base.common.Constant.Constant;
import org.jeecg.modules.zhima.base.exception.ApiException;
import org.jeecg.modules.zhima.base.shiro.service.TokenService;
import org.jeecg.modules.zhima.center.entity.UmsMember;
import org.jeecg.modules.zhima.portal.domain.Game;
import org.jeecg.modules.zhima.portal.domain.GamePlayer;
import org.jeecg.modules.zhima.portal.domain.OrderPrepayReturn;
import org.jeecg.modules.zhima.portal.domain.Player;
import org.jeecg.modules.zhima.portal.enums.*;
import org.jeecg.modules.zhima.portal.service.*;
import org.jeecg.modules.zhima.rule.GameRuleManager;
import org.jeecg.modules.zhima.rule.IGameRule;
import org.jeecg.modules.zhima.rule.domain.Rule;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GameServiceImpl implements IGameService {

    @Autowired
    private IZmGameService zmGameService;
    @Autowired
    private IZmGameAwardService zmGameAwardService;
    @Autowired
    private IZmGamePlayerService zmGamePlayerService;
    @Autowired
    private IGamePlayerService gamePlayerService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IPlayerService playerService;
    @Autowired
    private IPayService payService;
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IPlayerRankingService playerRankingService;
    @Autowired
    private IZmGameBackupService zmGameBackupService;
    @Autowired
    private IGameRuleService gameRuleService;

    @Override
    public IPage<Game> page(Page<ZmGame> page, QueryWrapper<ZmGame> queryWrapper) {
//        queryWrapper.gt("status", GameStatus.WAIT_CHECK);
        IPage<ZmGame> zmGameIPage = zmGameService.page(page, queryWrapper);
        return zmGameIPage.convert(this::fill);
    }

    @Override
    public List<Game> home() {
        List<ZmGame> zmGameList = zmGameService.list(new LambdaQueryWrapper<ZmGame>()
            .eq(ZmGame::getStatus, GameStatus.PUBLISH.CODE)//未开赛的赛事
            .orderByDesc(ZmGame::getCreateTime)
            .last("limit 5")
        );
        List<Game> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(zmGameList)){
            result = zmGameList.stream().map(this::fill).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public Game publish(Game game) {
        UmsMember umsMember = tokenService.getLoginUser();
        game.setUserId(umsMember.getId()+"");
        if (StringUtils.isBlank(umsMember.getJob()) || "admin".equals(umsMember.getJob())){
            //TODO 职业为空，为普通用户，发布积分赛;QP = 抢票赛赛事发布员
            game.setType(GameType.TYPE_1.CODE);
            ZmGameRule zmGameRule = gameRuleService.getByCode(GameRuleCode.JF.CODE);
            if (ObjectUtils.isNotEmpty(zmGameRule)){
                if (zmGameRule.getJoinRule().equals(GameJoinRule.RMB.CODE)||zmGameRule.getJoinRule().equals(GameJoinRule.JF.CODE)){
                    game.setEntryFee(zmGameRule.getJoinNum());
                }
//                if (zmGameRule.getAwardRule().equals(GameAwardRule.SUAN_FA.CODE) && StringUtils.isNotBlank(zmGameRule.getAwardId())){
//                    //TODO 调用算法计算奖励
                game.setAward(zmGameRule.getAward());
//                }

            }else {
                game.setEntryFee(new BigDecimal(10));
            }
        }else if(GameType.TYPE_2.RULE_CODE.equals(umsMember.getJob())) {
            //为特定用户，可发布抢票赛
            game.setType(GameType.TYPE_2.CODE);
            ZmGameRule zmGameRule = gameRuleService.getByCode(GameRuleCode.QP.CODE);
            if (ObjectUtils.isNotEmpty(zmGameRule)){
                if (zmGameRule.getJoinRule().equals(GameJoinRule.RMB.CODE)||zmGameRule.getJoinRule().equals(GameJoinRule.JF.CODE)){
                    game.setEntryFee(zmGameRule.getJoinNum());
                }
                game.setAward(zmGameRule.getAward());
            }else {
                game.setEntryFee(new BigDecimal(10));
            }
        }
        game.setCalculateStatus(Constant.GAME_CALCULATE_STATUS_DEFAULT);
        game.setStatus(GameStatus.WAIT_CHECK.CODE);
        game.setCreateTime(new Date());
        zmGameService.save(game);
        return game;
    }

    @Override
    public Game getById(String id) {
        ZmGame zmGame = zmGameService.getById(id);
        return fill(zmGame);
    }

    @Override
    public OrderPrepayReturn join(Game g) {
        Game game = this.getById(g.getId());
        if (ObjectUtils.isEmpty(game)){
            throw new ApiException("未知赛事");
        }
        UmsMember umsMember = tokenService.getLoginUser();
        Player player = playerService.getOrAdd(""+umsMember.getId());
        ZmGamePlayer zmGamePlayer = gamePlayerService.getOneByUserId(g.getId(), ""+umsMember.getId());
        if (zmGamePlayer != null){
            //重复报名 或 报名未付款
            ZmPayOrder zmPayOrder = payOrderService.getByGamePlayerId(zmGamePlayer.getId());
            if (zmPayOrder != null && zmPayOrder.getStatus() == 0){
                //报名未付款
                ZmGamePlayer gamePlayer = gamePlayerService.getOnePlayerId(game.getId(), player.getId());
                return payService.createJoinOrder(game.getEntryFee(), gamePlayer.getId());
            }
            return null;
        }
        Date now = new Date();
        //创建报名记录
        ZmGamePlayer joinGamePlayer = new ZmGamePlayer();
        joinGamePlayer.setGameId(g.getId());
        joinGamePlayer.setPlayerId(player.getId());
        joinGamePlayer.setScore(0L);
        joinGamePlayer.setRanking(0);
        joinGamePlayer.setIntegral(0.00);
        joinGamePlayer.setCreateTime(now);
        zmGamePlayerService.save(joinGamePlayer);
        //创建排行榜
        ZmPlayerRanking zmPlayerRanking = playerRankingService.getByPlayerId(player.getId());
        if (ObjectUtils.isEmpty(zmPlayerRanking)){
            zmPlayerRanking = new ZmPlayerRanking();
            zmPlayerRanking.setPlayerId(player.getId());
            zmPlayerRanking.setType(game.getType());
            zmPlayerRanking.setSourceId(game.getId());
            zmPlayerRanking.setScore(0L);
            zmPlayerRanking.setSort(0);
            zmPlayerRanking.setCreateTime(now);
            playerRankingService.save(zmPlayerRanking);
        }
        //报名人员信息同步
        Player p = g.getPlayer();
        if (ObjectUtils.isNotEmpty(player)
                && ObjectUtils.isNotEmpty(p)
                && ObjectUtils.isNotEmpty(p.getName())
                && ObjectUtils.isNotEmpty(p.getPhone())){
            player.setName(p.getName());
            player.setPhone(p.getPhone());
            playerService.updateById(player);
        }
        return payService.createJoinOrder(game.getEntryFee(), joinGamePlayer.getId());
    }

    @Override
    public Boolean unJoin(String gameId) {
        UmsMember umsMember = tokenService.getLoginUser();
        ZmGamePlayer zmGamePlayer = gamePlayerService.getOneByUserId(gameId, ""+umsMember.getId());
        if (zmGamePlayer != null){
            //删除报名付款记录
            payOrderService.removeAndRefund(zmGamePlayer.getId());
            //删除报名记录
            return gamePlayerService.removeById(zmGamePlayer.getId());
        }
        return false;
    }

    @Override
    public List<Game> listMyJoin(List<String> gameIds, int status) {
        List<Game> games = new ArrayList<>();
        for (String id: gameIds) {
            Game game = getById(id);
            if (status != 0 && status != game.getStatus()){
                continue;
            }
//            game = fill(game);
            games.add(game);
        }
        return games;
    }

    @Override
    public List<Game> listPublish(String userId, int status) {
        List<ZmGame> zmGameList = zmGameService.list(new LambdaQueryWrapper<ZmGame>().eq(ZmGame::getUserId, userId).eq(ZmGame::getStatus, status));
        List<Game> games = new ArrayList<>();
        for (ZmGame zmGame: zmGameList
             ) {
            Game game = new Game();
            BeanUtils.copyProperties(zmGame, game);
            fill(game);
            games.add(game);
        }
        return games;
    }

    @Override
    public List<Game> listMyJoin(Game game) {
        UmsMember member = tokenService.getLoginUser();
        if (ObjectUtils.isEmpty(member)){
            return Collections.EMPTY_LIST;
        }
        ZmPlayer player = playerService.getByUserId(""+member.getId());
        if (player == null){
            return Collections.EMPTY_LIST;
        }
        //报名记录
        List<ZmGamePlayer> zmGamePlayerList = zmGamePlayerService.list(new LambdaQueryWrapper<ZmGamePlayer>().eq(ZmGamePlayer::getPlayerId, player.getId()));
        List<String> gameIds = zmGamePlayerList.stream().filter(zmGamePlayer -> payOrderService.checkPayStatusRemote(zmGamePlayer.getId())).map(ZmGamePlayer::getGameId).collect(Collectors.toList());
        return listMyJoin(gameIds, game.getStatus());
    }

    @Override
    public List<Game> myPublish(Game game) {
        UmsMember member = tokenService.getLoginUser();
        if (ObjectUtils.isEmpty(member)){
            return Collections.EMPTY_LIST;
        }
        return listPublish(""+member.getId(), game.getStatus());
    }

    @Transactional
    @Override
    public boolean finish(Game game) {
        ZmGame zmGame = zmGameService.getById(game.getId());
        if (zmGame == null){
            return false;
        }
        Date now = new Date();
        zmGame.setStatus(GameStatus.FINISH.CODE);
        zmGame.setUpdateTime(now);
//        zmGame.setEndTime(now); //结赛时间，后期根据此时间计算积分修改冻结时间
        return zmGameService.updateById(zmGame);
    }

    @Override
    public boolean cancel(Game game) {
        ZmGame zmGame = zmGameService.getById(game.getId());
        List<GamePlayer>  gamePlayerList = gamePlayerService.listJoiners(zmGame.getId());
        if (CollectionUtils.isNotEmpty(gamePlayerList)){
            gamePlayerList.forEach(gamePlayer -> {
                payOrderService.removeAndRefund(gamePlayer.getId());
            });
        }
        zmGame.setStatus(GameStatus.DELETE.CODE);
        zmGame.setUpdateTime(new Date());
        zmGameService.updateById(zmGame);
        return true;
    }

    @Override
    public boolean edit(ZmGame zmGame) {
        backup(zmGame);
        ZmGame old = zmGameService.getById(zmGame.getId());
        BigDecimal enteryFee = old.getEntryFee();
        BeanUtils.copyProperties(zmGame, old);
        old.setEntryFee(enteryFee);
        old.setUpdateTime(new Date());
        return zmGameService.updateById(old);
    }

    @Override
    public boolean delay(ZmGame zmGame) {
        backup(zmGame);
        ZmGame old = zmGameService.getById(zmGame.getId());
        old.setStartTime(zmGame.getStartTime());
        old.setUpdateTime(new Date());
        return zmGameService.updateById(old);
    }

    @Transactional
    @Override
    public List<Game> calculate() {
        List<Game> gameList = new ArrayList<>();
        Calendar calculateTime = Calendar.getInstance();
        //TODO 结算赛事后，计算积分的延迟时间
        calculateTime.add(Calendar.HOUR, -24);
//        calculateTime.add(Calendar.MINUTE, 0);
        List<ZmGame> zmGameList = zmGameService.list(new LambdaQueryWrapper<ZmGame>()
                .eq(ZmGame::getType, GameType.TYPE_1.CODE) //已结赛
                .eq(ZmGame::getStatus, GameStatus.FINISH.CODE) //已结赛
                .eq(ZmGame::getCalculateStatus, 0) //未计分
                .isNotNull(ZmGame::getEndTime)
//                .le(ZmGame::getEndTime, calculateTime)
        );
        if (CollectionUtils.isNotEmpty(zmGameList)){
            Date now = new Date();
            for (ZmGame g: zmGameList) {
                if (calculateTime.getTime().before(g.getEndTime())){
                    continue;
                }
                //参赛选手
                List<GamePlayer> gamePlayerList = gamePlayerService.listJoiners(g.getId());
                if (CollectionUtils.isNotEmpty(gamePlayerList)) {
                    ZmGameRule zmGameRule = gameRuleService.getByCode(GameType.get(g.getType()).RULE_CODE);
                    if (zmGameRule.getAwardRule().equals(GameAwardRule.SUAN_FA.CODE)){
                        //依据动态算法结算奖励
                        IGameRule gameRule = GameRuleManager.getInstance(zmGameRule.getAwardId());
                        List<String> playerIds = gamePlayerList.stream().map(ZmGamePlayer::getPlayerId).collect(Collectors.toList());
                        //赛事排行榜
                        List<ZmPlayerRanking> zmPlayerRankingList = playerRankingService.list(playerIds);
                        for (int i = 0; i < gamePlayerList.size(); i++) {
                            ZmGamePlayer zmGamePlayer = gamePlayerList.get(i);
                            Rule rule = new Rule();
                            rule.setGameId(g.getId());
                            rule.setJoinNum(gamePlayerList.size());
                            rule.setRanking(i+1);
                            double integral = gameRule.getIntegral(rule);
                            boolean flag = false;

                            //更新选手参赛次数，计算奖励积分
                            playerService.playSuccess(zmGamePlayer.getPlayerId());

                            for (ZmPlayerRanking ranking: zmPlayerRankingList) {
                                if (zmGamePlayer.getPlayerId().equals(ranking.getPlayerId())){
                                    ranking.setScore(zmGamePlayer.getScore());
                                    ranking.setIntegral(ranking.getIntegral()+integral);
                                    ranking.setUpdateTime(now);
                                    playerRankingService.updateById(ranking);
                                    flag = true;
                                }
                            }
                            if (!flag){
                                ZmPlayerRanking ranking = new ZmPlayerRanking();
                                ranking.setScore(zmGamePlayer.getScore());
                                ranking.setIntegral(integral);
                                ranking.setCreateTime(now);
                                ranking.setType(g.getType());
                                ranking.setPlayerId(zmGamePlayer.getPlayerId());
                                ranking.setSort(0);
                                ranking.setSourceId(g.getId());
                                playerRankingService.save(ranking);
                            }
                            //更新比赛选手列表结算状态
                            zmGamePlayer.setStatus(GameStatus.PUBLISH.CODE);
                            zmGamePlayer.setIntegral(integral);
                            zmGamePlayer.setUpdateTime(now);
                            zmGamePlayerService.updateById(zmGamePlayer);
                        }

                        //赛事举办方奖励
                        playerService.playSuccess(g.getUserId(), playerIds.size());

                    }
                }
                //修改赛事计分状态
                g.setCalculateStatus(Constant.GAME_CALCULATE_STATUS_FINISH);
                g.setUpdateTime(now);
                zmGameService.updateById(g);
            }
        }
        return gameList;
    }

    public static void main(String[] args) {
        Calendar calculateTime = Calendar.getInstance();
        //TODO 结算赛事后，计算积分的延迟时间
        calculateTime.add(Calendar.HOUR, 24);
//        calculateTime.add(Calendar.MINUTE, 0);
        Date now = new Date();
        System.out.println(now);
        System.out.println(calculateTime.getTime());
        System.out.printf(""+now.before(calculateTime.getTime()));
    }
    private Game fill(ZmGame zmGame){
        if (zmGame == null){
            return null;
        }
        Game game = new Game();
        BeanUtils.copyProperties(zmGame, game);
        return this.fill(game);
    }

    private Game fill(Game game){
        //1、校验开赛时间，更改赛事状态
        Date date = new Date();
        if (game.getStartTime().before(date) && game.getStatus().equals(GameStatus.PUBLISH.CODE)){
            game.setStatus(GameStatus.ACTIVATED.CODE);
            zmGameService.updateById(game);
        }
        //2、修改报名费单位：分->元
        game.setEntryFee(game.getEntryFee().divide(new BigDecimal(100)));
        //3、赛事类型文案：积分、抢票、掘金
        game.setTypeTxt(GameType.get(game.getType()).VALUE);
        //4、赛事状态文案
        game.setStatusTxt(GameStatus.get(game.getStatus()).VALUE);
        //5、比赛形式文案：1、重量赛，2、尾数赛
        game.setScoreTypeTxt(GameScoreType.get(ObjectUtils.isNotEmpty(game.getScoreType())?game.getScoreType():0).VALUE);
        //6、参赛选手
        List<GamePlayer> gamePlayerList = gamePlayerService.listJoiners(game.getId());
        game.setJoinNum(CollectionUtils.isEmpty(gamePlayerList)?0:gamePlayerList.size());
        game.setPlayers(gamePlayerList);
        UmsMember member = tokenService.getLoginUser();
        if (ObjectUtils.isNotEmpty(member)){
            ZmPlayer zmPlayer = playerService.getByUserId(""+member.getId());
            if (ObjectUtils.isNotEmpty(zmPlayer)){
                //7、本人参赛信息
                GamePlayer gamePlayer = gamePlayerService.getOnePlayerId(game.getId(), zmPlayer.getId());
                game.setGamePlayer(gamePlayer);
                if (ObjectUtils.isNotEmpty(gamePlayer)){
                    //8、报名付款信息
                    ZmPayOrder zmPayOrder = payOrderService.getByGamePlayerId(gamePlayer.getId());
                    game.setPayOrder(zmPayOrder);
                }
            }
        }
        return game;
    }

    private void backup(ZmGame zmGame){
//        ZmGameBackup zmGameBackup = zmGameBackupService.getById(zmGame.getId());
        ZmGameBackup zmGameBackup = new ZmGameBackup();
        ZmGame old = zmGameService.getById(zmGame.getId());
        zmGameBackup.setGameId(old.getId());
        BeanUtils.copyProperties(old, zmGameBackup);
        zmGameBackup.setId(null);
        zmGameBackupService.save(zmGameBackup);
    }

}
